module mculib.arm.uart;
import mculib.chip;


version(None):


private enum bool hasBusPeriph = HasPeriph!("USART1","USART2","USART3","UART4","UART5","USART6");
static if (hasBusPeriph):

import arm.bus;
import arm.rcc;
import arm.gpio;
import arm.stk;

static interface UAA(alias mPeri)
{
    version(none) enum USART1_Type* mBase = Peripherals.USART1;
    else enum mBase = mPeri;
    enum string IFName = __traits(identifier, mPeri);


    static void Enable() => (mBase.CR1.UE = 1);
    static void Disable() => (mBase.CR1.UE = 0);
    static void IsEnable() => (mBase.CR1.UE == 1);
    
    
}

static interface UART(alias mPeri,alias mGPIOx)// : MMIOBus!(mPeri) 
{
    package{
        enum FlagUsartPort
        {
            Usart1_A = 0
        }

        enum FlagUsartMode
        {
            DMA,
            Interrupt,
        }

        /// 数据宽度
        enum FlagDataWidth
        {
            /// 8 位
            DataWidth_8 = 0,
            /// 9 位
            DataWidth_9 = 1
        }
        /// 停止位标志
        enum FlagStop
        {
            /// 1 停止位
            Stop_1 = 0,
            /// 2 停止位
            Stop_2 = 1,
        }
        /// 传输模式
        enum FLagMode
        {
            none
        }

        /// 
        enum FlagParity
        {
            none
        }

        /// 串口配置
        struct UsartConf_Type
        {
            /// 传输波特率
            uint baudrate;
            /// 传输模式
            FlagUsartMode mode;
            /// 数据宽度
            FlagDataWidth dataWidth;
            /// 停止位
            FlagStop stop;
            /// 校验位
            FlagParity parity;
        }
    }

    private{
        /// 配置名称
        enum IFName = __traits(identifier, mPeri);
        /// 编写代码时临时使用
        version(none) enum USART6_Type* mBase = Peripherals.USART1;
        else enum mBase = mPeri;
        /// 停止位
        enum FlagSTOP
        {
            /// 1 停止位
            STOP_1 = 0,
            /// 0.5 停止位
            STOP_0_5 = 1,
            /// 2 停止位
            STOP_2 = 2,
            /// 1.5 停止位
            STOP_1_5 = 3
        }
        /// 工作模式
        enum FlagModer
        {
            None = 0,           /// 无
            Async = 1,          /// 异步
            Sync = 2,           /// 同步
            HalfDuplex = 3,     /// 半双工
            SingleLine = 4,     /// 单线
            SmartCard = 5,      /// 智能卡
            IrDA = 6,           /// 红外
            MultiProcess = 7    ///  MultiProcess 模式
        }

        ///异步
        static void ModeAsync()
        {
            with ( mBase.mask_CR2 )
            {
                mBase.CR2 &= ~(LINEN|CLKEN);
            }
            with ( mBase.mask_CR3 )
            {
                mBase.CR3 &= ~(SCEN | IREN | HDSEL);
            }
        }
        /// 同步
        static void ModeSync()
        {
            with ( mBase.mask_CR3 )
            {
                mBase.CR3 &= ~(SCEN|IREN|HDSEL);
            }
            with ( mBase.mask_CR2 )
            {
                mBase.CR2 &= ~LINEN;
                mBase.CR2 |= CLKEN;
            }
        }
        /// 半双工
        static void ModeHalfDuplex()
        {
            with ( mBase.mask_CR3 )
            {
                mBase.CR3 &= ~(SCEN|IREN);
                mBase.CR3 |= HDSEL;
            }
            with ( mBase.mask_CR2 )
            {
                mBase.CR2 &= ~(LINEN|CLKEN);
            }
        }
        /// 全双工
        /// 单线
        static void ModeSingleLine()
        {
            with ( mBase.mask_CR3 )
            {
                mBase.CR3 &= ~(IREN|SCEN|HDSEL);
            }
            with ( mBase.mask_CR2 )
            {
                mBase.CR2 &= ~(CLKEN|STOP);
                mBase.CR2 |= LINEN;
            }
        }
        /// 智能卡
        static void ModeSmartCard()
        {
            with ( mBase.mask_CR3 )
            {
                mBase.CR3 &= ~(IREN|HDSEL);
                mBase.CR3 |= SCEN;
            }
            with ( mBase.mask_CR2 )
            {
                mBase.CR2 &= ~(LINEN);
                mBase.CR2.STOP = FlagSTOP.STOP_1_5;
                mBase.CR2.CLKEN = 1;
            }
        }
        /// 红外
        static void ModeIrDA()
        {
            with ( mBase.mask_CR3 )
            {
                mBase.CR3 &= ~(SCEN|HDSEL);
                mBase.CR3 |= IREN;
            }
            with ( mBase.mask_CR2 )
            {
                mBase.CR2 &= ~(LINEN|CLKEN | STOP);
            }
        }
        ///  MultiProcess 模式
        static void ModeMultiProcess()
        {
            with ( mBase.mask_CR3 )
            {
                mBase.CR3 &= ~(SCEN|HDSEL|IREN);
            }
            with ( mBase.mask_CR2 )
            {
                mBase.CR2 &= ~(LINEN|CLKEN);
            }
        }

    }
    
    pragma(inline,true);
    static void Init()
    {
        /// 设置端口

        RCC.Power!(IFName ~ "EN")(1);
        
    }
    /// 配置异步模式
    static void ConfigAsync(UsartConf_Type conf)()
    {
        // 1. 使能时钟
        //RCC.Power!(mName ~ "EN")(1);
        // 2. 配置波特率
        // 3. 配置传输模式
        // 4. 配置数据宽度
        // 5. 配置停止位
        // 6. 配置校验位
        // 7. 配置硬件流控制
        // 8. 配置中断
        // 9. 使能串口
        
        //mBase.CR2 = 

        
    }

    static void Enable() => (mBase.CR1 |= mBase.mask_CR1.UE);
    static void Disable() => (mBase.CR1 &= ~mBase.mask_CR1.UE);
    static bool isEnabled() => ((mBase.CR1 & mBase.mask_CR1.UE) != 0);

    ///  私有
    private{
        pragma(crt_constructor,CrtPriority!(FlagCrt.Other,0))
        static this()
        {
            //import arm.rcc;
            //RCC.Power!(IFName ~ "EN")(1);
            Init();
        }
    }
    /// 收发数据
    public{
        // -- 发送
        static void Send(ubyte data)
        {
            while(!mBase.SR.TXE){}          /// 判定前一次发送是否已经发送到移位寄存器
            mBase.DR = data;                /// 发送数据到缓冲寄存器

        };
        static bool Send(ubyte* src,size_t count,bool wait)
        {
            foreach(i;0..count)
                Send(src[i]);


            return mBase.SR.TC == 1;
        }
        static bool Send(ubyte[] data,bool wait = false)
        {
            return Send(data.ptr,data.length,wait);
        }
        // -- 接收
        static ubyte Recv()
        {
            return cast(ubyte)mBase.DR;
        }
        static void Recv(ubyte* dst,size_t count)
        {
            foreach(i;0..count)
                dst[i] = Recv();
        }


    }
}

/// 异步传输
final abstract class UARTAsync(bool flow=false) : PeripheralStream
{
    /// 发送数据
    static void write1(scope ubyte* src,in size_t len)
    {
        Monitor.lock();
    }

    /// 接收数据
}


alias UsartPort = GPIO!(Peripherals.GPIOB,PortMask.Pin6|PortMask.Pin7);
alias Usart1 = UART!(Peripherals.USART1,UsartPort);
//alias Usart2 = UARTAsync!(true);



//pragma(msg,"as:",);